﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Elderos.Controls
{
    public class ValidatableTextBox : TextBox
    {
        public ValidatableTextBox()
        {
            this.PreviewTextInput += ValidatableTextBox_PreviewTextInput;
            this.TextChanged += ValidatableTextBox_TextChanged;
            DataObject.AddPastingHandler(this, ValidatableTextBox_HandlePaste);
        }

        void ValidatableTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            IsIncorrectValue = !InvokeFinalValidation(this.Text);
        }

        public string DefaultValue
        {
            get { return (string)GetValue(DefaultValueProperty); }
            set { SetValue(DefaultValueProperty, value); }
        }



        public bool IsIncorrectValue
        {
            get { return (bool)GetValue(IsIncorrectValueProperty); }
            set { SetValue(IsIncorrectValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsIncorrectValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsIncorrectValueProperty =
            DependencyProperty.Register("IsIncorrectValue", typeof(bool), typeof(ValidatableTextBox), new UIPropertyMetadata(false));

        // Using a DependencyProperty as the backing store for DefaultValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DefaultValueProperty =
            DependencyProperty.Register("DefaultValue", typeof(string), typeof(ValidatableTextBox), new UIPropertyMetadata(""));

        public string Value
        {
            get
            {
                if (IsIncorrectValue)
                    return DefaultValue;
                return this.Text;
            }
        }

        private void ValidatableTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            string text = (sender as TextBox).Text + e.Text;
            if (!InvokeValidate(text)) 
                e.Handled = true;
        }

        private void ValidatableTextBox_HandlePaste(object sender, DataObjectPastingEventArgs args)
        {
            if (args.DataObject.GetDataPresent(typeof(string)))
            {
                var text = (string)args.DataObject.GetData(typeof(string));
                if (!InvokeValidate(text)) args.CancelCommand();
            }
            else 
                args.CancelCommand();
        }

        public event Func<string, bool> FinalValidation;

        public bool InvokeFinalValidation(string text)
        {
            Func<string, bool> handler = FinalValidation;
            if (handler != null) return handler(text);
            return InvokeValidate(text);
        }

        public event Func<string, bool> Validate;

        public bool InvokeValidate(string text)
        {
            Func<string, bool> handler = Validate;
            if (handler != null)
            {
                bool result = handler(text);
                return result;
            }
            return true;
        }

        public static bool ValidateDouble(string arg)
        {
            bool hasDot = false;
            foreach (char ch in arg)
            {
                if (char.IsDigit(ch)) continue;
                if (!new[] { ',', '.' }.Contains(ch))
                    return false;
                if (hasDot) return false;
                hasDot = true;
            }
            return true;
        }

        public static bool ParseDouble(string arg)
        {
            double value;
            return double.TryParse(arg.Replace(",", "."), NumberStyles.Number, CultureInfo.InvariantCulture, out value);
        }

        public static bool ValidateDoubleCollection(string arg)
        {
            string[] doubles = arg.Split(new[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries);
            return doubles.All(ValidateDouble);
        }

        public static bool ParseDoubleCollection(string arg)
        {
            string[] doubles = arg.Split(new[] { " ", "\t" }, StringSplitOptions.RemoveEmptyEntries);
            return doubles.All(ParseDouble);
        }

    }
}
